#include <cassert>
#include <cstdio>
#include <iostream>
#include <iostream>
#include <vector>
#include "Cell.h"

using namespace std;

template <typename T>
class Life {
	private:
		/**
		* @param stepCount Global containing number of evolve steps
		*/
		int stepCount;
		/**
		* @param rows rows in the board
		*/
		int rows;
		/**
		* @param cols cols in the board
		*/
		int cols;
		/**
		* @param neighbors live neighbor counts
		*/
		std::vector< std::vector< std::vector<int> > > neighbors;
		/**
		* @param map map of the cells
		*/
		std::vector< std::vector<T> > map;

	public:

	/**
 	* constructs empty c x r board
 	* @param r number of rows
	* @param c number of cols
 	*/
	//TODO this constructor is really inefficent....too much copying
	Life(int r, int c){
		stepCount=0;
		rows=r;
		cols=c;

		vector<T> temp(rows+2);
		vector<vector<T> > temp1(cols+2,temp);
		map=temp1;

		vector<int> temp2(rows+2);
		vector<vector<int> > temp3(cols+2,temp2);
		vector<vector<vector<int> > > temp4(2,temp3);
		neighbors=temp4;
	}

	/**
 	* constructor using istream containing board info
 	* @param in istream from file or stdin with board info
 	*/
	//TODO this constructor is really inefficent....too much copying
	Life(std::istream& in){
		stepCount=0;
		in>>rows;
		in>>cols;
		in.get();
		int r=0;
		int c=0;
		
		
	
		vector<T> temp(rows+2);
		vector<vector<T> > temp1(cols+2,temp);
		map=temp1;

		vector<int> temp2(rows+2);
		vector<vector<int> > temp3(cols+2,temp2);
		vector<vector<vector<int> > > temp4(2,temp3);
		neighbors=temp4;

		char t;
		while(!in.eof()){
			while(in.peek() != '\n' && !in.eof()){
				in>>t;
				map[c+1][r+1].setCell(t);
				++c;
			}
			in.get();
			++r;
			c=0;
		}
	}

	/**
 	* evolves the board one generation
 	*/
	void step(){
		T::resetNeighborCount(neighbors);
		for(int x=1; x<=cols; ++x){
			for(int y=1; y<=rows; ++y){
				
				if(map[x][y].isAlive()){
					map[x][y].updateNeighborCount(neighbors,x,y);
				}
			}
		}
		for(int x=1; x<=cols; ++x){
			for(int y=1; y<=rows; ++y){
					map[x][y].evolve(neighbors,x,y);
			}
		}
		++stepCount;
		
		
		
	}

	/**
 	* counts the number of live cells
	* @return number of live cells
 	*/

	//TODO This could be optimized by tracking population else where like evolve()
	int getPopulation(){
		int count=0;
		for(int x=1; x<map.size()-1;++x){
			for(int y=1;y<map[0].size()-1; ++y){
				if(map[x][y].isAlive())
					++count;
			}
		}
		return count;
	}

	/**
 	* prints board and stats
 	*/
	void print(){
		printf("Generation = %d, Population = %d.\n",stepCount,getPopulation());
		for(int y=1;y<map[0].size()-1;++y){
			for(int x=1;x<map.size()-1;++x){
				map[x][y].print();
			}
			puts("");	
		}
		puts("");
	}

	bool operator == (Life<T>& l){
		try{
		for(int x=1;x<map.size()-1;++x){
			for(int y=1;y<map[0].size()-1;++y){
				if(!(map.at(x).at(y)==l.getCell(x,y)))
					return false;
			}
		}

		}catch(exception& e){return false;}
		return true;
	}

	T& getCell(int x, int y){
		return map.at(x).at(y);
	}

	/**
 	* debug helper method. prints data structures 
 	*/
	void printStructure(){
		printf("Step %d",stepCount);
		puts("");
		puts("");
		for(int y=0;y<map[0].size();++y){
			for(int x=0;x<map.size();++x){
				map[x][y].print();
			}
			puts("");	
		}
		puts("\n");
		
		for(int z=0; z<1;++z){
			for(int y=0;y<map[0].size();++y){
				for(int x=0;x<map.size();++x){
					printf("%d",neighbors[z][x][y]);
				}
				puts("");	
			}
			puts("\n");
		}
	}

	
};
